package br.com.winesys.geta.databinding.component.selector;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import br.com.winesys.geta.databinding.component.listeners.SelectionListener;
import br.com.winesys.geta.databinding.component.table.TableModel;
import br.com.winesys.geta.databinding.component.table.TableViewer;
import br.com.winesys.geta.editor.Editor;

public abstract class ObjectLocator<Entity> {

    private JDialog dialog;
    private JPanel buttonsPanel;
    private JButton updateButton;
    private JButton cancelButton;
    private JButton selectButton;
    private TableViewer<Entity> table;
    private Entity selected;
    private List<Entity> findable;
    private SelectionListener<Entity> listener;

    public ObjectLocator(Window parent, SelectionListener<Entity> listener) {
        this.dialog = new JDialog(parent, "Localizar Item");
        this.listener = listener;
        this.dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        this.dialog.setModal(true);

        this.buttonsPanel = new JPanel();

        this.selectButton = new JButton("Selecionar");
        this.selectButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent evt) {
                ObjectLocator.this.doSelect();
            }
        });

        this.cancelButton = new JButton("Cancelar");
        this.cancelButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent evt) {
                ObjectLocator.this.doCancel();
            }
        });

        this.updateButton = new JButton("Atualizar");
        this.updateButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent evt) {
                ObjectLocator.this.doList();
            }
        });

        GroupLayout buttonsPanelLayout = new GroupLayout(this.buttonsPanel);
        this.buttonsPanel.setLayout(buttonsPanelLayout);
        buttonsPanelLayout.setHorizontalGroup(buttonsPanelLayout.createParallelGroup(Alignment.LEADING).addGroup(Alignment.TRAILING, buttonsPanelLayout.createSequentialGroup().addContainerGap().addComponent(this.updateButton).addPreferredGap(ComponentPlacement.RELATED, 350, Short.MAX_VALUE).addComponent(this.selectButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addPreferredGap(ComponentPlacement.RELATED).addComponent(this.cancelButton).addContainerGap()));
        buttonsPanelLayout.linkSize(SwingConstants.HORIZONTAL, new Component[]{this.updateButton, this.cancelButton});
        buttonsPanelLayout.setVerticalGroup(buttonsPanelLayout.createParallelGroup(Alignment.LEADING).addGroup(Alignment.TRAILING, buttonsPanelLayout.createSequentialGroup().addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addGroup(buttonsPanelLayout.createParallelGroup(Alignment.BASELINE).addComponent(this.cancelButton).addComponent(this.updateButton).addComponent(this.selectButton, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)).addContainerGap()));
        this.dialog.getContentPane().add(this.buttonsPanel, BorderLayout.SOUTH);

        this.table = createTableView();
        this.dialog.getContentPane().add(this.table, BorderLayout.CENTER);
        this.table.addSelectionListener(new SelectionListener<Entity>() {

            @Override
            public void itemSelected(Entity object) {
                ObjectLocator.this.selectButton.setEnabled(object != null);
                ObjectLocator.this.selected = object;
            }
        });
        this.table.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    e.consume();
                    doSelect();
                }
            }
        });
        this.dialog.getRootPane().setDefaultButton(this.selectButton);
        this.dialog.getRootPane().registerKeyboardAction(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                doCancel();
            }
        }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);

        this.dialog.doLayout();
        this.dialog.pack();
    }

    private TableViewer<Entity> createTableView() {
        TableViewer<Entity> visualizador = new TableViewer<Entity>() {

            @Override
            protected Editor<?> createFilter() {
                return ObjectLocator.this.createFilter();
            }

            @Override
            protected TableModel<Entity> createTableModel() {
                return ObjectLocator.this.createTableModel();
            }
        };
        return visualizador;
    }

    protected abstract void getValues();

    protected Editor<?> createFilter() {
        return null;
    }

    protected abstract TableModel<Entity> createTableModel();

    private void doList() {
        if (this.findable != null) {
            this.table.setValues(this.findable);
        } else {
            this.getValues();
        }
    }

    public void setList(List<Entity> items) {
        this.table.setValues(items);
    }

    private void doSelect() {
        this.listener.itemSelected(this.selected);
        this.dialog.setVisible(false);
    }

    private void doCancel() {
        this.dialog.setVisible(false);
    }

    public void run() {
        doList();
        this.selectButton.setEnabled(false);
        Point center = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
        this.dialog.setLocation((int) center.getX() - (this.dialog.getWidth() / 2), (int) center.getY() - (this.dialog.getHeight() / 2));
        this.dialog.setVisible(true);
    }
}
